#include "EpilFunctionStatementInterpreter.h"
#include "EpilInterpreterException.h"
#include "EpilInterpreter.h"
#include "EpilFunctionBodyExpressionInterpreter.h"


EpilFunctionStatementInterpreter::EpilFunctionStatementInterpreter( EpilInterpreter * interpreter )
: EpilInterpreterBase( interpreter )
{
}


void EpilFunctionStatementInterpreter::Run( const EpilFunctionStatementCode * code )
{
	EpilFunctionBodyExpressionInterpreter ebei( this->GetInterpreter() );
	ebei.Run( code->GetBody() );
	EpilScriptFunctionObject * funcObj = ebei.GetFunction();

	const EpilFunctionNameCode * nameCode = code->GetFunctionName();
	if( nameCode->GetTableNames().empty() )
	{
		this->GetInterpreter()->SetGlobalVariable( nameCode->GetName(), funcObj );
		return;
	}

	EpilObject * globalObj = this->GetInterpreter()->GetGlobalVariable( t("_G") );
	EpilTableObject * curTable = static_cast<EpilTableObject*>( globalObj );
	const list<tstring> & tableNames = nameCode->GetTableNames();
	for( list<tstring>::const_iterator it = tableNames.begin(); it != tableNames.end(); ++it )
	{
		EpilObject * newObj = curTable->GetField( *it );
		if( newObj->GetType() != EOT_Table )
		{
			funcObj->ReleaseCopy();
			newObj->ReleaseCopy();
			curTable->ReleaseCopy();
			throw EpilInterpreterException( t("Attempt to index a non-table value: \'") + *it + t("\'."), nameCode->GetLocation() );
		}
		EpilTableObject * newTable = static_cast<EpilTableObject*>( newObj );
		curTable->ReleaseCopy();
		curTable = newTable;
	}

	if( nameCode->IsMethod() )
	{
		funcObj->GetParameters().push_front( t("self") );
	}

	curTable->SetField( nameCode->GetName(), funcObj );

	curTable->ReleaseCopy();
}